/***********************************************************************************************
 * Brocade FC Switch CLI 'cfgShow' Reply ZONE configuration informations ->
 * zone.VM1_SC8K:VM1;SC8K_VIR
 * zone.hs22_1_md3620f:20:12:f0:1f:af:d5:c3:9d;20:23:f0:1f:af:d5:c3:9d;21:00:00:24:ff:55:8c:c2
 * zone.hs22_1_sc8k:21:00:00:24:ff:55:8c:c2;SC8K_VIR
 * zone.m1000e0slot4_md3620f:20:12:f0:1f:af:d5:c3:9d;20:23:f0:1f:af:d5:c3:9d;m1000e0_slot4
 * Phase#1 : Parse "cfgSave" log by lines.
 * Phase#2 : Generate "zoneCreate" command
 *           Generate "zoneDelete" command
***********************************************************************************************/
#include <regex.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>

typedef struct __zone_config_sentense
{
    char zName[32];
    char zMember[32][128];
    int nMember;
}ZCFG;

void clearZCFG(ZCFG* zcfg)
{
    zcfg->nMember = 0;
    memset(zcfg->zName, 0, 32);
    for(int i = 0; i < 32; i++){ memset(zcfg->zMember[i], 0, 128); }
}

/*
*/
int cfgParse(const char* cfg, ZCFG* zcfg)
{
    /* Phase#1: Get "zoneName" & "zoneMembers" through RegEx */
    regex_t re;  regmatch_t matches[32];
    /**************** EDITTING Regular expression *****************/
    const char *RegEx = "zone.([^:]+):(\\S+)";
    /**************************************************************/
    int re_ret = regcomp(&re, RegEx, REG_EXTENDED); 
    assert(re_ret == 0);
    re_ret = regexec(&re, cfg, sizeof(matches)/sizeof(matches[0]), (regmatch_t*)&matches, 0); 
    //assert(re_ret == 0);
    if(re_ret != 0 ){
        zcfg->nMember = 0;
        return 1;
    }
    // Clean zone members' memory space.
    clearZCFG(zcfg);
    char sMember[1024];
    for(int idx = 1; idx <= re.re_nsub; idx++){
        char *val = strndup(cfg+matches[idx].rm_so,  matches[idx].rm_eo-matches[idx].rm_so);
        //fprintf(stdout, "Value[$%d] -> %s\n", idx, val);  
        if(idx == 1){ strcpy(zcfg->zName, val); }
        else if(idx == 2){ strcpy(sMember, val); }
        free(val);
    }
    regfree(&re);
    
    /* Phase#2: Split "zoneMembers" */
    zcfg->nMember = 0;
    for(int i = 0, c = 0; i < strlen(sMember); i++){   
        //Splitor charactor: ';'
        if(sMember[i] == ';'){ zcfg->nMember++; c = 0; }
        else{
            zcfg->zMember[zcfg->nMember][c++] = sMember[i];
        }
    }
    zcfg->nMember++;
    return 0;
}

int zcfgPrint(ZCFG* zcfg)
{
    if(zcfg->nMember == 0)
        return 1;
    char bufDelete[2048]; sprintf(bufDelete, "zoneDelete \"%s\"", zcfg->zName);
    char bufCreate[2048]; 
    
    regex_t re;  regmatch_t matches[8]; char newZone[256]; memset(newZone, 0, 256);
    /**************** EDITTING Regular expression *****************/
    const char *RegEx = "(\\S+)(8[kK])(\\S*)";
    /**************************************************************/
    int re_ret = regcomp(&re, RegEx, REG_EXTENDED); 
    assert(re_ret == 0);
    re_ret = regexec(&re, zcfg->zName, sizeof(matches)/sizeof(matches[0]), (regmatch_t*)&matches, 0); 
    //assert(re_ret == 0);
    if(re_ret != 0)
        return 2;
    for(int idx = 1; idx <= re.re_nsub; idx++){
        char *val = strndup(zcfg->zName+matches[idx].rm_so,  matches[idx].rm_eo-matches[idx].rm_so);
        //fprintf(stdout, "Value[$%d] -> %s\n", idx, val);  
        if(strcmp(val, "8k") == 0 || strcmp(val, "8K") == 0) 
            val[0] = '9';   //Replace from '8' to '9'
        strcat(newZone, val);
        free(val);
    }
    regfree(&re);
    //fprintf(stdout, "newZone: %s\n", newZone);
    sprintf(bufCreate, "zoneCreate \"%s\", \"", newZone);
    for(int i = 0; i < zcfg->nMember; i++){
        strcat(bufCreate, zcfg->zMember[i]);
        if(i < (zcfg->nMember-1))
            strcat(bufCreate, "; ");
    }
    strcat(bufCreate, "\"");
    fprintf(stdout, "%s\n%s\n", bufCreate, bufDelete);
    return 0;
}

/* Usage -> 
 * $ ./zoneRename ../doc/6510_2.txt
 */
int main(int argc, char* argv[])
{
    ZCFG zcfg; char lineBuffer[1024]; FILE *fp;
    if( (fp=fopen(argv[1], "r")) == NULL ){
        fprintf(stderr, "Failed to open Configuration file!\n");
        return 1;
    }
    
    while (fgets(lineBuffer, sizeof(lineBuffer), fp) != NULL)
    {
        int re_ret = cfgParse((const char*)lineBuffer, &zcfg);
        if(re_ret == 0){
            //printf("----------------------------------------------------------\n%s", lineBuffer);
            zcfgPrint(&zcfg);
        }
        memset(lineBuffer, 0, sizeof(lineBuffer));
    }

    fclose(fp);
    return 0;
}